package ferp.core.mode;

import ferp.core.calc.Calculator;
import ferp.core.card.Card;
import ferp.core.game.Bid;
import ferp.core.game.Game;
import ferp.core.game.Input;
import ferp.core.game.Settings;
import ferp.core.player.Player;
import ferp.core.player.Profile;
import ferp.core.state.State;

/**
 * User: olegs
 * Date: 19/05/11 15:11
 */
public class Contracting extends Mode
{
  @Override
  public int initialize(Game.Listener listener, Profile profile, Game g, Settings settings) throws Game.Error
  {
    int r = super.initialize(listener, profile, g, settings);

    // clear number of passers and whisters
    g.passers = 0;
    g.whisters = 0;
    // clear half-whister
    g.player.half = Game.NO_ID;
    // reset opponent and passer
    g.player.opponent = Game.NO_ID;
    g.player.passer = Game.NO_ID;

    return r;
  }

  @Override
  public Card.State getTalonCardState(Game g, Settings settings, int i) {return Card.State.HIDDEN;}

  @Override
  public void score(Game g, Settings settings)
  {
    Calculator c = Calculator.get(settings.gameFlavor);

    if (g.whisters == 0)
    {
      if (g.passers == 2 && g.player.half == Game.NO_ID)
      {
        // contracting has been finished with 2 passers
        g.setTricks(g.player.declarer, g.contract());
        c.trickingTwoPasses(g, settings);
      }
      else
      {
        // contracting has been finished with half-whister and passer
        int whists = Calculator.getExpectedStandingWhists(g.contract());

        g.setTricks(g.player.half, whists);
        g.setTricks(g.player.declarer, 10 - whists);

        c.trickingHalfWhist(g, settings);
      }

      if (settings.isPassingInterruptedByNonWhistedGame())
        g.consequentPassingSets = 0;
    }
    else
    {
      // called after 'fast moving' task has been completed
      c.tricking(g, settings);

      if (g.getDeclarerTricks() >= g.contract() || settings.isPassingInterruptedByFailedGame())
        g.consequentPassingSets = 0;
    }
  }

  @Override
  protected int getStartingPlayer(Game g)
  {
    // make declarer to be the starting player
    return g.player.declarer;
  }

  @Override
  protected int getFirstPlayer(Game g)
  {
    // if we do not have half-whister yet behave normally
    if (g.player.half == Game.NO_ID)
      return super.getFirstPlayer(g);

    // if we have half-whister move the current hand to the player next to the declarer
    g.hand = 1;

    return Game.next(g.player.declarer);
  }

  @Override
  protected int options(Game.Listener listener, Game g, Settings settings, Input input) throws Game.Error
  {
    Player p = g.current();

    if (p == g.declarer())
    {
      // declare tricking game greater or equal to the highest bid
      g.options.set(Input.Options.DECLARE);
      g.options.bid.assign(g.bid);
    }
    else
    {
      Bid contract = g.getDeclarerBid().current;

      // if Stalingrad game declared don't turn on any input options for opponents - whist bid will be assigned automatically in act method
      if (contract.isStalingrad(settings))
        return State.Result.SCHEDULE;

      if (contract.check10(settings))
        return p.setContractingInputOptionsCheck10(g.options);

      // any non-declarer player may always say pass or whist
      g.options.set(Input.Options.WHIST_PASS | Input.Options.WHIST_FULL);

      Player previous = g.previous(p);

      // if previous non-declarer player said pass and game is 6 or 7 - this player may also say half whist
      // if (previous != g.declarer && previous.bid.current.pass())
      if (g.canHalfWhist() && g.getBid(previous.id()).current.isPass())
      {
        g.options.set(Input.Options.WHIST_HALF);
        g.options.clear(Input.Options.WHIST_PASS);
      }
    }

    return p.setContractingInputOptions(g.options);
  }

  @Override
  protected Act act(Game.Listener listener, Game g, Settings settings, Input input) throws Game.Error
  {
    // delegate to the current player
    g.current().contract(g, settings, input);

    Bid contract = g.getDeclarerBid().current;

    if (contract.check10(settings))
      return act10(listener, g, settings, input);

    // force whist on 6 of spades
    if (g.player.current != g.player.declarer && contract.isStalingrad(settings))
      g.getCurrentPlayerBid().current.type = Bid.Type.WHIST;

    // update number of passers/whisters depending on the player action performed
    if (g.getCurrentPlayerBid().current.isPass())
    {
      g.player.passer = g.player.current;
      ++g.passers;
    }
    else
      if (g.getCurrentPlayerBid().current.isWhist())
      {
        // set the opponent (main whister)
        g.player.opponent = g.player.current;
        ++g.whisters;
      }
      else
        if (g.getCurrentPlayerBid().current.isHalfWhist())
          g.player.half = g.player.current;

    listener.onPlayerContract(g.current(), g.getCurrentPlayerBid());

    return Act.NEXT;
  }

  @Override
  protected boolean isSetOver(Game g)
  {
    // number of passers/whisters has reached its nominal value
    return g.passers + g.whisters == 2;
  }

  @Override
  protected void done(Game.Listener listener, Game g, Settings settings)
  {
    // fire contracting end event
    listener.onContractingEnd();

    if (g.check10)
    {
      if (g.declarer() == g.human())
        g.set(State.ttc);
      else
        g.set(Mode.tricking10);

      return;
    }

    // if two players both said whist then play standing
    if (g.whisters == 2)
    {
      g.type = Game.Type.STANDING;
      // clear opponent and passer
      g.player.opponent = Game.NO_ID;
      g.player.passer = Game.NO_ID;
    }

    // switch to the dropping mode only if there is a game to be played
    if (g.passers < 2)
    {
      // if there was a half-whister change his bid to pass
      if (g.player.half != Game.NO_ID)
      {
        g.player.passer = g.player.half;
        g.getHalfBid().current.type = Bid.Type.PASS;
        // fire event
        listener.onPlayerContract(g.passer(), g.getPasserBid());
      }

      // choose an appropriate mode depending on the game declared
      if (g.declarer() != g.human() && g.getBid(g.human().id()).current.isPass() && settings.skipGameOnPass)
        g.set(State.fastMoving);
      else
        g.set(Mode.tricking);
    }
    else
      g.score();
  }

  @Override
  protected void next(Game g)
  {
    // means half-whister is a current player - must go to other passer to let him to make final decision
    // the other passer should have already made his decision - jump to the round end
    if (g.rounds > 0)
      exit(g);
    else
      super.next(g);
  }

  private Act act10(Game.Listener listener, Game g, Settings settings, Input input)
  {
    if (g.player.current == g.player.declarer)
    {
      boolean dh = g.declarer() == g.human();
      Player p = g.declarer();

      for (int i = 0; i < Game.PLAYERS; ++i)
      {
        g.getHand(p.id()).open = true;
        listener.onOpenPlayerCards(g, settings, p.id());

        if (p == g.declarer() || !dh)
          listener.onPlayerContract(p, g.getBid(p.id()));

        p = g.next(p);
      }
    }
    else
    {
      g.current().setCheck10(g, input);
      ++g.passers;
    }

    return Act.NEXT;
  }
}
